package com.aner.tester.generator.param;

import com.aner.tester.generator.TypeManager;
import com.aner.tester.generator.data.ValueGenerator;
import com.aner.tester.object.MethodObject;
import com.aner.tester.object.ValueObject;
import com.aner.tester.utils.ReflectUtils;

import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 *  the form data method of parameter generator
 *
 * @author aner
 * @version 1.0
 * @date 2020/12/14 14:21
 */
public class FormDataGenerator extends ParameterGenerator {

    Map<String, Object> paramMap = new LinkedHashMap<>();
    Object object;
    private MethodObject methodObject;

    public FormDataGenerator(MethodObject methodObject) {
        this.methodObject = methodObject;
    }

    @Override
    public Object generate() {
        generateValue();
        return object == null ? paramMap: object;
    }

    /**
     *  the object parameter that has RequestBody annotation or has no annotation
     *  must be resolved to key-value(<fieldName, fieldValue>) method,
     *  which is different to the one that has RequestParam annotation.
     */
    @Override
    protected void generateValue() {

        List<ValueObject> valueObjectList = methodObject.getValueObjects();
        if (valueObjectList.size() == 1
                && TypeManager.customContains(valueObjectList.get(0).getTypeName())
                && !ValueType.REQUEST_PARAM.equals(valueObjectList.get(0).getValueType())  ) {
            this.object = ValueGenerator.generateCustom(valueObjectList.get(0).getTypeName(), valueObjectList.get(0).getLevelCount());
            return;
        }
        for(ValueObject valueObject: valueObjectList) {
             if (TypeManager.customContains(valueObject.getTypeName())
                     && !ValueType.REQUEST_PARAM.equals(valueObject.getValueType())){
                Object value = ValueGenerator.generateCustom(valueObject.getTypeName(), valueObject.getLevelCount());
                 if (value != null) {
                     putCustomValue(value);
                 }
            } else {
                 if (ValueType.REQUEST_PARAM.equals(valueObject.getValueType())) {
                     valueObject.setLevelCount(valueObject.getLevelCount() - 1);
                 }
                 Object value = ValueGenerator.generate(valueObject);
                 putValue(valueObject.getName(), value);
             }
        }
    }

    public void putValue(String name, Object object) {
        paramMap.put(name, object);
    }

    public void putCustomValue(Object object) {
        try {
            Field[] fields = ReflectUtils.getFields(object.getClass());
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(object);
                putValue(field.getName(), value);
            }
        } catch (Exception e) {
            logger.info("the nested level of custom type is not supported");
        }
    }
}
